home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Suntar 1.3.2 / diskDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-31  |  36.1 KB  |  1,285 lines  |  [TEXT/KAHL]

  1. /*******************************************************************************\
  2.  
  3. disk driver interface module
  4.  
  5. suntar 1.3.2, ©1991-92 Sauro & Gabriele Speranza
  6.  
  7. This program is public domain, feel free to use it or part of it for anything
  8.  
  9. \*******************************************************************************/
  10.  
  11.  
  12. #include "PB_sync.h"
  13. #include "antiglue.h"
  14.  
  15. #ifndef THINK_C_5
  16. #include    <DiskDvr.h>
  17. #include    <DeviceMgr.h>
  18. #else
  19. #include    <Disks.h>
  20. #include    <files.h>
  21. #define ioRefNum ioCRefNum
  22. #endif
  23.  
  24. #include "windows.h"
  25. #include "suntar.h"
  26.  
  27. #define dp printf
  28.  
  29. #define SINGLE_SIDED    2
  30. #define TWO_SIDED    3
  31. #define SUPERDRIVE    4
  32.  
  33.  
  34. extern short n_superdrives,last_drive,preferred_drive;
  35. extern short drive_type[max_drive];
  36. extern Boolean disco_espulso;
  37. extern sector_t file_current_s;
  38.  
  39. static short Sony_driver;
  40. /*#define Sony_driver -5 */
  41.  
  42. OSErr get_format(DrvSts*,char*);
  43. Boolean is_msdos_disk(short);
  44. void verify_sectors(sector_t,char *,short);
  45.  
  46. short FindDriverByName( void *);
  47.  
  48. enum os_type riconosci_disco_mac(sector_2)
  49. unsigned char sector_2[512];
  50. {
  51. /* sector 2 contains the essential informations about the disk in both MFS and HFS */
  52. enum os_type i;
  53.  
  54. if( *(short*) sector_2== 0xD2D7 )
  55.     i=mac_MFS;
  56. else if( *(short*) sector_2== 0x4244)
  57.     i=mac_HFS;
  58. else
  59.     return unknown_os;
  60.  
  61. if( sector_2[36]<=27 /*lunghezza del nome*/ &&
  62.         *(short*)§or_2[12]>0 /* numero di files nel disco */)
  63.     return i;
  64.  else
  65.      return unknown_os;    /* two possible 16 bit values means 1 probability
  66.                          out of 32768 to recognize as Mac disk a non-Mac one,
  67.                          testing some other fields decreases it... */
  68. }
  69.  
  70.  
  71. static Boolean is_msdos_disk(drive_n)
  72. short drive_n;
  73. {
  74. /* ms-dos does not define a field containing some fixed value, but some
  75. fields are much larger than the small numbers they should hold, hence there is much
  76. redundancy, if all those fields have reasonable values, and at least some are not
  77. zero, then it must be an ms-dos disk
  78. Attention ! It uses the value of sectors_on_floppy which must be set to the correct
  79. value for the disk
  80. */
  81.  
  82. struct bootsector {        /* from mtools, msdos.h */
  83. /*0*/    unsigned char jump[3];        /* Jump to boot code */
  84. /*3*/    unsigned char banner[8];    /* OEM name & version */
  85. /*11*/    unsigned char secsiz[2];    /* Bytes per sector hopefully 512 */
  86. /*13*/    unsigned char clsiz;        /* Cluster size in sectors */
  87. /*14*/    unsigned char nrsvsect[2];    /* Number of reserved (boot) sectors */
  88. /*16*/    unsigned char nfat;            /* Number of FAT tables hopefully 2 */
  89. /*17*/    unsigned char dirents[2];    /* Number of directory slots */
  90. /*19*/    unsigned char psect[2];        /* Total sectors on disk */
  91. /*21*/    unsigned char descr;        /* Media descriptor=first byte of FAT */
  92. /*22*/    unsigned char fatlen[2];    /* Sectors in FAT */
  93. /*24*/    unsigned char nsect[2];        /* Sectors/track */
  94. /*26*/    unsigned char nheads[2];    /* Heads */
  95. /*28*/    unsigned char nhs[2];        /* number of hidden sectors */
  96. /*30*/    unsigned char junk[482];    /* who cares? */
  97. };
  98.  
  99.  
  100. unsigned char buffer[512];
  101. short i;
  102. unsigned short n_s;
  103. Boolean maybe_old;
  104. static unsigned char offs[]= {11,12,13,15,16,18,23,25,26,27};
  105. static unsigned char limit[]={0, 2, 4, 0, 2, 2, 0, 0, 2, 0};
  106. static unsigned char min[]=  {0, 2, 0, 0, 1, 0, 0, 0, 1, 0};
  107.  
  108. read_one_sector(0,buffer,drive_n);
  109. if(err_code) return false;
  110.  
  111. maybe_old=false;
  112. for(i=0;i<sizeof(offs);i++)
  113.     if((unsigned char)buffer[offs[i]]>limit[i] ||
  114.        (unsigned char)buffer[offs[i]]<min[i]){
  115.         if(i<7) return false;
  116.         maybe_old=true;    /* those fields don't exist in disks formatted by a very 
  117.                         old version of ms-dos */
  118.         }
  119.  
  120. lowbyte(n_s)= buffer[19];
  121. highbyte(n_s)= buffer[20];
  122.  
  123. if(buffer[24]==0 || n_s != sectors_on_floppy || n_s%buffer[24]!=0 )
  124.     maybe_old=true;
  125.         /* bisogna accettare 9 e 18 ma anche 8 (160K) e 16 (320K) e 15 (1200K) 
  126.         e tanto vale anche un numero di settori qualunque purche' multiplo intero 
  127.         del numero di settori per traccia (a meno che l'hardware possa fornire i 
  128.         "veri" valori per questi parametri)
  129.         -- I can't test the exact value of sectors per track since somebody
  130.         could find a way to connect to the .Sony driver a disk which is not
  131.         720 nor 1440, but 360, 1200 or even the now obsolete 180, 160 and 320K
  132.         formats
  133.         */
  134. if(!maybe_old) return true;
  135. /* pero' in quei casi, la FAT sta comunque nel settore 1 e il primo byte della
  136. FAT (byte 0) vale FE o FC o FD o FF a seconda della densita' (160,180,320,360)
  137. -- in very old DOS some of the test variables were not defined, the remaining
  138. ones are too few to guarantee good probabilities of correctly guessing, but
  139. in those cases the FAT is in sector 1 and the first byte of FAT is
  140. FE or FC or FD or FF according to the density (160,180,320,360)
  141. */
  142. if(buffer[21]>=0xFC /* && buffer[21]<=0xFF */)
  143.     return true;
  144. read_one_sector(1,buffer,drive_n);
  145. if(!err_code && buffer[0]>=0xFC)
  146.     return true;
  147. return false;
  148. }
  149.  
  150. /***********************************************************************/
  151.  
  152.  
  153. static Handle icon_handle;
  154. static Rect iconRect={10,16,42,48};
  155.  
  156.  
  157. pascal Boolean icon_update (DialogPtr,EventRecord *,short *);
  158. static pascal Boolean icon_update (theDialog, theEvent,itemHit)
  159. /* update routine for the disk initialization dialog: we've tried to
  160. copy the standard disk initialization dialog used by DIBadMount
  161. */
  162. DialogPtr theDialog;
  163. EventRecord *theEvent;
  164. short *itemHit;
  165. {
  166. if(theEvent->what==keyDown &&  ((unsigned char) theEvent->message==enter_key || 
  167.    (unsigned char) theEvent->message==CR)){
  168.     Rect frameRect;
  169.     short    kind;
  170.     Handle    h;
  171.     *itemHit=1;
  172.     GetDItem(theDialog,1,&kind,&h,&frameRect);
  173.     SelectButton(h);
  174.     return true;
  175.     }
  176. else if(theEvent->what==updateEvt){
  177.     if((WindowPtr)theEvent->message==theDialog){
  178.         GrafPtr    savePort;
  179.         Rect frameRect;
  180.         short    kind;
  181.         Handle    h;
  182.  
  183.         GetPort( &savePort );    
  184.         SetPort(theDialog);
  185.         PlotIcon(&iconRect,icon_handle);
  186.         GetDItem(theDialog,1,&kind,&h,&frameRect);
  187.         OutlineControl(h);
  188.  
  189.         SetPort(savePort);
  190.         }
  191.     else
  192.         UpdateFilter(theEvent);
  193.     }
  194. else if(theEvent->what==activateEvt)
  195.         UpdateFilter(theEvent);
  196.  
  197. return false;
  198. }
  199.  
  200.  
  201. void disk_format(make_dir)        /* disk initialization routine */
  202. Boolean make_dir;
  203. {
  204. /* see Technical Notes 70 and 272 */
  205.  
  206. extern Point badmount_point;
  207. cntrlParam       ParamBlock;
  208. DialogTHndl    dHandle;
  209. DialogPtr myDialog;
  210. short item,err;
  211.  
  212.  
  213.     /* per dischi da 720K voglio usare un formato non ottenibile dalla DIBadMount, 
  214.     per gli altri voglio evitare la caratteristica del System 7 che accetta anche
  215.     dischi con settori difettosi, quindi devo fare tutto da solo, compreso un dialogo 
  216.     possibilmente simile a quello standard
  217.     -- 720K disks can't be obtained by DIBadMount. Other formats can, but System 7
  218.     may return a noErr code for disks with bad sectors, marking them in the allocation
  219.     table, hence it's better to avoid DIBadMount in any case. However, the user
  220.     will feel better if my dialog looks like the standard disk initialization dialog
  221.     */
  222.  
  223. invalid_buffers();
  224. if( di.supports_720K){
  225.     di.format_index=di.supports_720K;    /* format_index contains the value for 800k, the
  226.         maximum size, but I don't want that format */
  227.     di.max_format=1440;
  228.     }
  229.  
  230. SetCursor(&arrow);
  231. /* procurati l'icona da mettere nel dialogo*/
  232. ParamBlock.ioRefNum=Sony_driver;
  233. ParamBlock.ioVRefNum=drive_number;
  234. ParamBlock.csCode=21;                    /* Return Physical Drive Icon */
  235. /*ParamBlock.ioCompletion=NULL; no, non serve se la chiamata è sincrona */
  236. icon_handle=NewHandle(128);        /* la routine ritorna un Ptr, ma PlotIcon vuole 
  237.                     un handle e la Apple sconsiglia vivamente di crearsi un handle 
  238.                     senza passare per NewHandle...
  239.                     -- I get a Ptr, but PlotIcon needs an handle and Apple discourages
  240.                     to create an handle without calling NewHandle, that could crash
  241.                     the machine, hence I must create a legal handle and copy the data
  242.                     */
  243. if( PBControlSync(&ParamBlock) != noErr)
  244.     fillmem(*icon_handle,0,128);
  245. else
  246.     mcopy(*icon_handle, *((Ptr*)&ParamBlock.csParam[0]), 128);
  247.  
  248. /* crea e posiziona il dialogo */
  249. dHandle = (DialogTHndl)Get1Resource('DLOG',132);
  250. if (dHandle) {
  251.     char buff[8];
  252.     HLock((Handle)dHandle);
  253.     PositionDialog( &((**dHandle).boundsRect));
  254.     myDialog=GetNewDialog(132,NULL,(WindowPtr)-1L);
  255.     if(in_Italia){
  256.         short    kind;
  257.         Handle    h;
  258.         Rect    r;
  259.         GetDItem(myDialog,1,&kind,&h,&r);
  260.         SetCTitle(h,di.is_not_initialized?"\pEspelli":"\pAnnulla");
  261.         GetDItem(myDialog,2,&kind,&h,&r);
  262.         SetCTitle(h,"\pInizializza");
  263.         }
  264.     else if(di.is_not_initialized){
  265.         short    kind;
  266.         Handle    h;
  267.         Rect    r;
  268.         GetDItem(myDialog,1,&kind,&h,&r);
  269.         SetCTitle(h,"\pEject");
  270.         }
  271.     my_itoa((long)(di.max_format>>1),&buff);
  272.     my_c2pstr(buff);
  273.     if(di.is_not_initialized)
  274.         ParamText(in_Italia ? "\pDisco non inizializzato, verrà inizializzato a " :
  275.             "\pUninitialized disk, it will be initialized at ",
  276.             buff,"\p Kbytes",PNS);
  277.     else
  278.         ParamText(in_Italia ? "\pIl disco verrà inizializzato\ra " :
  279.             "\pThis disk will be initialized\rat ", buff,"\p Kbytes",PNS);
  280.  
  281.     ModalDialog(icon_update,&item);
  282.  
  283.     if(item!=2){
  284.         if(di.is_not_initialized) diskEject();
  285.         }
  286.     else{
  287.         short     *IPtr;
  288.         GrafPtr    savePort;
  289.         static Rect rectScritta={0,54,40,300};    /* abbondare non nuoce */
  290.         GetPort( &savePort );    
  291.         SetPort(myDialog);
  292.         for(item=1;item<=3;item++){
  293.             short    kind;
  294.             Handle    h;
  295.             Rect    r;
  296.             GetDItem(myDialog,item,&kind,&h,&r);
  297.             InsetRect(&r,-4,-4);
  298.             EraseRect(&r);
  299.             }
  300.         MoveTo(64,20);
  301.         DrawString(in_Italia ? "\pInizializzazione..." :"\pInitializing...");
  302.         PlotIcon(&iconRect,icon_handle);    /* ci fosse un update non servito...*/
  303.         SetCursor(&waitCursor);
  304.  
  305.         {CntrlParam parblk;
  306.         char*pt=&parblk.csParam;
  307.         parblk.ioRefNum=Sony_driver;
  308.         parblk.ioVRefNum=drive_number;
  309.         parblk.csCode=9;                    /* Track Cache Control */
  310.         pt[0]=0;                    /* disable */
  311.         pt[1]=-1;                    /* remove */
  312.         PBControlSync(&parblk);
  313.         }
  314.  
  315.         ParamBlock.ioRefNum=Sony_driver;
  316.         ParamBlock.ioVRefNum=drive_number;        /*1 for internal -- 2 for external drive*/
  317.         ParamBlock.csCode=6;                    /*Format control code*/
  318.         IPtr= (short*)&ParamBlock.csParam;           /*point to it; pretend it's an int */
  319.         *IPtr=di.format_index;                        /* see TN 272 */
  320.  
  321.         FlushVol(PNS,drive_number);
  322.         di.disk_code=noMacDskErr;
  323.         err=PBControlSync(&ParamBlock);
  324.  
  325.         {CntrlParam parblk;
  326.         char*pt=&parblk.csParam;
  327.                 /* the initialization has changed the content of the disk,
  328.                 but the content of the track cache are NOT automatically
  329.                 invalidated, at least not always (it's not random, since when it
  330.                 happens it happens regularly, but I've not found any cause for 
  331.                 that) hence I disable the track cache, do a write to be sure,
  332.                 and enable it again. I do not guarantee that it's OK now, since
  333.                 when it does not happen it does not happen regularly, and I
  334.                 can't do hundreds of formatting just to verify...*/
  335.  
  336.         fillmem(disk_buffer,0xF6,512);
  337.         write_sectors(0,disk_buffer,1);
  338.         parblk.ioRefNum=Sony_driver;
  339.         parblk.ioVRefNum=drive_number;
  340.         parblk.csCode=9;                    /* Track Cache Control */
  341.         pt[0]=1;            /* enable */
  342.         pt[1]=1;            /* install */
  343.         PBControlSync(&parblk);
  344.         }
  345.  
  346.         if(err==noErr){
  347.  
  348.             EraseRect(&rectScritta);
  349.             MoveTo(64,20);
  350.             DrawString(in_Italia ? "\pVerifica..." :"\pVerifying...");
  351.             if(DIVerify(drive_number) == noErr){
  352.                 if(make_dir){
  353.                     EraseRect(&rectScritta);
  354.                     MoveTo(64,20);
  355.                     DrawString(in_Italia ? "\pCreazione catalogo..." :"\pCreating directory...");
  356.                     di.disk_code=DIZero (drive_number,di.max_format==1440 ? "\p720 Kbytes volume" :
  357.                         "\pUntitled");
  358.                     FlushVol (PNS,drive_number);    /* contro le stranezze del system 7 che spesso lo
  359.                         richiede immediatamente dopo averlo espulso */
  360.                     UnmountVol(NULL,drive_number);
  361.                     }
  362.                 }
  363.             else{
  364.                 beep_in_foreground();
  365.                 printf(in_Italia ? "Verifica fallita\n":"Verification failed\n");
  366.                 diskEject();
  367.                 }
  368.             }
  369.         else{
  370.             beep_in_foreground();
  371.             printf(in_Italia?"Inizializzazione fallita\n":"Initialization failed\n");
  372.             diskEject();
  373.             }
  374.         SetPort(savePort);
  375.         SetCursor(&arrow);
  376.         }
  377.     HUnlock ((Handle)dHandle);
  378.     DisposDialog(myDialog);
  379.     /*update_console();*/
  380.     DisposHandle(icon_handle);
  381.     }
  382. }
  383.  
  384.  
  385. /************** testa stato ************/
  386.  
  387. short testa_stato(inPlace,verbose)
  388. /* calls the device driver to get informations about the current disk,
  389. then does some testing for useful data that the driver does not know;
  390. informations are returned in inPlace and the global variables di.is_write_protected,
  391. sectors_on_floppy , di.is_not_initialized, di.os (useful for any disk),
  392. di.max_format, di.format_index, di.supports_720K (useful only if the disk
  393. need be initialized)
  394. */
  395.  
  396. short *inPlace;
  397. Boolean verbose;
  398. {
  399. short i;
  400. OSErr err;
  401. DrvSts status;
  402. char sector_buffer[512];
  403.  
  404. read_one_sector(0,sector_buffer,drive_number);    /* well, the write protected field
  405.     of status may be incorrect if I don't do that before. Don't ask me why */
  406. i=5;
  407. do{    /* vedi get_format sul perché faccio questo */
  408.     err=DriveStatus(drive_number,&status);
  409.     if(err) read_one_sector(0,sector_buffer,drive_number);
  410.     }
  411. while(--i && err!=noErr);
  412. if(err){
  413.     if(verbose){
  414.         start_of_line();
  415.         printf("Disk drive error %d\n",err);
  416.         }
  417.     return -1;
  418.     }
  419.  
  420. *inPlace=status.diskInPlace;
  421.  
  422. err=get_format(&status,sector_buffer);
  423. if(err!=noErr){
  424.     if(verbose) printf("Disk driver error\n");
  425.     return -1;
  426.     }
  427.  
  428. /* discover if the disk is not initialized: there is not a device driver call
  429. for this purpose, but that range of errors is typical for non-initialized disks */
  430.  
  431. read_one_sector(2,sector_buffer,drive_number); 
  432. if(    (di.is_not_initialized = err_code<=-66 && err_code>=-71) ){
  433.     di.os=unknown_os;
  434.     di.disk_code=ioErr;
  435.  
  436.     if(sectors_on_floppy==800){
  437.         sectors_on_floppy=1600;
  438.         if(verbose) printf(in_Italia?"Disco non inizializzato da 400/800/720 Kbytes\n":
  439.             "400/800/720 Kbytes disk, not initialized\n");
  440.         }
  441.     else if(verbose)
  442.         printf(in_Italia?"Disco non inizializzato da %ld Kbytes\n":
  443.             "%ld Kbytes disk, not initialized\n",(long)sectors_on_floppy>>1);
  444.  
  445.     return 0;
  446.     }
  447. if(err_code!=noErr) read_one_sector(2,sector_buffer,drive_number); 
  448. if(err_code){
  449.     disk_error_message();
  450.     di.disk_code=err_code;
  451.     di.os=unknown_os;
  452.     return noErr;
  453.     }
  454.  
  455. di.os=riconosci_disco_mac(sector_buffer);
  456. if(di.os==unknown_os){
  457.     di.disk_code=noMacDskErr;
  458.     if(is_msdos_disk(drive_number) ){
  459.         di.os=msdos;
  460.         if(verbose){
  461.             one_empty_line();
  462.             printf(in_Italia?"Questo è un disco MS-DOS da %ldK\n":
  463.                 "MS-DOS %ldK disk\n",(long)sectors_on_floppy>>1);
  464.             }
  465.         }
  466.     else if(verbose){
  467.         one_empty_line();
  468.         printf(in_Italia?"Disco da %ldK\n":"%ldK disk\n", (long)sectors_on_floppy>>1);
  469.         }
  470.     }
  471. else{
  472.     di.disk_code=noErr;
  473.     if(verbose){
  474.         one_empty_line();
  475.         printf(in_Italia ? "Questo è un disco Macintosh da %ldK\n" :
  476.             "Macintosh %ldK disk\n", (long)sectors_on_floppy>>1);
  477.         }
  478.     }
  479.  
  480. return noErr;
  481. }
  482.  
  483. Boolean is_wrprot()
  484. {
  485.     DrvSts status;
  486.  
  487.     if(file_aperto) return 1;
  488.  
  489.     DriveStatus(drive_number,&status);
  490.     return (status.writeProt&0x80) != 0;
  491. }
  492.  
  493. static OSErr get_format(status,buffer)
  494. DrvSts*status;
  495. char*buffer;    /* only to be used as temporary storage, it does not carry
  496.                 any information, but why allocate another buffer ? */
  497. {
  498. /* cerca il formato del disco attualmente nel drive; ritorna noErr se l'ha trovato,
  499. oppure il codice di errore ritornato dal device driver .Sony; poi, -1 se nessun
  500. formato è quello del disco corrente (disco assente ?). Nella variabile
  501. sectors_on_floppy lascia il numero di settori, valido solo per noErr; comunque
  502. aggiorna supports_720K;
  503. -- uses the new status calls to get informations about the current disk: it 
  504. may return the error code given by PBStatus, or noErr if succeeded, or -1
  505. if none of the supported disk formats is marked as being that of the current disk;
  506. supports_720K is adjusted in any case.
  507. */
  508. long tabella[12];
  509. CntrlParam parblk;
  510. short j;
  511. OSErr err;
  512.  
  513. /* a volte succede che inserisco il disco quasi insieme all'emissione del
  514. comando da menù, il disco viene espulso ma NON da parte della diskEject che libera
  515. il drive, ma da parte del chiamante che si vede ritornare -1 da testa_stato,
  516. perché la PBStatus ritorna offLinErr. Unica soluzione, fare una read appena
  517. prima, e certo riprovare più volte aiuta
  518. */
  519. j=5;
  520. do{
  521.     fillmem(&(parblk.qLink),0,sizeof(CntrlParam));
  522.     parblk.ioRefNum=Sony_driver;
  523.     parblk.ioVRefNum=drive_number;
  524.     parblk.csCode=6;
  525.     parblk.csParam[0]=6;    /* dim tabella */
  526.  
  527.     *(long*)(&(parblk.csParam[1])) = (long)&(tabella[0]);
  528.     err=PBStatusSync (&parblk.qLink);
  529.  
  530.     /*dp("err =%d(%d)\n",err,drive_number);*/
  531.     if(err==offLinErr) read_one_sector(0,buffer,drive_number);
  532.     }
  533. while(err==offLinErr&&--j);
  534. di.supports_720K=0;
  535.  
  536. if(err==statusErr){        /* non c'è una versione recente del device driver,
  537.             ma allora non supporta i SuperDrive e i formati possibili sono questi:
  538.             -- the device driver does not support the new status calls, but
  539.             old drivers don't support SuperDrives and DriveStatus suffices to
  540.             build the informations I need
  541.             */
  542.     sectors_on_floppy= (status->twoSideFmt==-1) ? 1600 : 800;
  543.     if(status->sides&0x80){
  544.         di.max_format=1600;
  545.         di.format_index=2;
  546.         }
  547.     else{
  548.         di.max_format=800;
  549.         di.format_index=1;
  550.         }
  551.     return noErr;
  552.     }
  553. else if(err != noErr)
  554.     return err;
  555.  
  556. sectors_on_floppy=0;
  557. /*di.format_index=0;*/
  558. di.max_format=-1;
  559. for(j=0;j<parblk.csParam[0];j++){
  560.     if(tabella[j+j+1] & 0x40000000L)    /* bit "current disk has this format" */
  561.         sectors_on_floppy=tabella[j+j];
  562.     if(tabella[j+j]==1440) di.supports_720K=j+1;
  563.     if(tabella[j+j]>di.max_format){
  564.         di.max_format=tabella[j+j];
  565.         di.format_index=j+1;
  566.         }
  567.     }
  568. /*sectors_on_floppy=100;    /*per le prove multivolume, mica voglio perdere tempo!
  569.                             -- for debugging multivolume formats, put few data
  570.                             on each disk, otherwise the tests will last hours ! */
  571. if(sectors_on_floppy==0) return -1;
  572. return noErr;
  573. }
  574.  
  575. void identifica_hardware()
  576. /* get informations about the .Sony device driver and the disk drives  */
  577. {
  578. /* i 4 LSB di parblk.csParam[1] valgono:
  579. -- from TN272: the four LSB of parblk.csParam[1] are coded as follows:
  580. 0    no such drive
  581. 1    unspecified drive
  582. 2    400K Sony
  583. 3    800K Sony
  584. 4    SuperDrive (400K/800K GCR, 720K/1440K MFM)
  585. 5    reserved
  586. 6    reserved
  587. 7    Hard Disk 20
  588. 8-15    reserved
  589.  
  590. anyway, since in the News somebody tells that Apple is going to put out
  591. a new floppy disk drive (maybe 2.88M, maybe a floptical 20M), suntar
  592. accepts 5 as a SuperDrive-compatible disk: there is no reason why Apple
  593. should not use that code nor make that drive SuperDrive-incompatible
  594. */
  595. CntrlParam parblk;
  596. short i,n_drives=0;
  597.  
  598. /* new for suntar 1.3.2: till now we've used the fixed number -5, and
  599. it always worked, but it's more elegant to use the name, one never knows
  600. what will happen on future Macs (or Mac-compatible operating systems...) */
  601. Sony_driver=FindDriverByName("\p.Sony");
  602. if(!Sony_driver) Sony_driver=-5;
  603.  
  604. n_superdrives=0;
  605. last_drive=0;
  606. for (i=1;i<=max_drive;i++){        /* ci possono essere buchi, ma comunque mai oltre l'unità 4 ! 
  607.                         -- a Macintosh can't go beyond unit 4, but there may be
  608.                         an hole since old systems assigned 3 to an external drive even 
  609.                         if unit 2 was not present
  610.                         */
  611.     drive_type[i-1]=0;
  612.     parblk.ioRefNum=Sony_driver;
  613.     parblk.ioVRefNum=i;
  614.     parblk.csCode=23;
  615.  
  616.     err_code=PBControlSync (&(parblk.qLink));
  617.     /*printf("%d %x %d\n",i,parblk.csParam[1],err_code);*/
  618.     if(err_code==controlErr){    /* una versione del disk driver anteriore a quella
  619.                                 che gestisce i SuperDrive
  620.                                 -- an old version of the device driver: get 
  621.                                 informations from DriveStatus
  622.                                 */
  623.         DrvSts status;
  624.         err_code=DriveStatus(drive_number,&status);    /* per sapere se il drive esiste */
  625.         if(err_code==noErr && status.installed>=0){
  626.             if(n_superdrives==0) preferred_drive=i;
  627.             last_drive=i;
  628.             n_drives++;
  629.             drive_type[i-1]= (status.sides&0x80) ? TWO_SIDED|0x8000 : SINGLE_SIDED|0x8000;
  630.             }
  631.         }
  632.     else if(err_code==noErr){    /* OK, può essere un SuperDrive */
  633.         short j;
  634.         drive_type[i-1]=parblk.csParam[1]&0x7FFF;
  635.         j= parblk.csParam[1] &0xF;
  636.         if(j==SUPERDRIVE || j==SUPERDRIVE+1){
  637.             preferred_drive=i;
  638.             n_superdrives++;
  639.             }
  640.         if(n_superdrives==0) preferred_drive=i;
  641.         last_drive=i;
  642.         n_drives++;
  643.         }
  644.     }
  645.  
  646. if(n_superdrives>1 || n_superdrives==0&&n_drives>1)
  647.     preferred_drive=0;
  648.  
  649.  
  650. #if 0        /* no more useful, since now I do my own buffering */
  651. if(preferred_drive){
  652.     parblk.ioRefNum=Sony_driver;
  653.     parblk.ioVRefNum=preferred_drive;
  654.     parblk.csCode=9;                    /* Track Cache Control */
  655.     *(short*)&parblk.csParam =1*256+1;    /* Track cache on: pare che sia la normalità, 
  656.                                         ma non si sa mai
  657.                                         -- track cache on: suntar is much faster. 
  658.                                         Really, that's the default mode on our Mac,
  659.                                         but we don't know about other Macs. Well, in
  660.                                         theory one should restore the original situation
  661.                                         when quitting, but there seems to be no easy
  662.                                         way to know which was the current setting:
  663.                                         "When the cache is removed, 680x0 register D0 
  664.                                         contains the previous size of the cache", 
  665.                                         (TN 272) but that does NOT work !, in D0
  666.                                         it always return 0 for noError, looking at D0.L,
  667.                                         D1.L and A0.L does not yield any number that
  668.                                         could be that thing
  669.                                         */
  670.  
  671.     PBControlSync(&parblk);
  672.     }
  673. #endif
  674.  
  675. if(n_superdrives==0 && !accetta_GCR){
  676.         ParamText(in_Italia ?
  677. "\pNon hai un SuperDrive, quindi non potrai\rleggere dischi scritti su un sistema UNIX":
  678. "\pYou have no SuperDrive, you can\'t read\rdisks written on an UNIX machine",
  679.         PNS,PNS,PNS );
  680.         my_alert();
  681.     }
  682.  
  683. }
  684.  
  685. /******************* buffering *********************************/
  686.  
  687. /* suntar either writes or reads, and when it does neither of the two
  688. it's better to flush the buffers anyway, since the disk could be ejected
  689. without letting him know. Hence it's better to let the buffer empty even
  690. in cases when the data is still good. Otherwise, this is a simple
  691. implementation of a write-back cache, consisting of a single "cache line" with
  692. status information for each sector.
  693.  
  694. Probably it would be faster using Async calls, but that's more difficult,
  695. and an old Apple Technical Note told that the first versions of MultiFinder
  696. did not let an application go to background while it had some Async calls
  697. pending.
  698. Really, in many cases the best thing would be to launch one independent Async
  699. call for each sector, so the operation will start as sooner as possible,
  700. with the highest degree of parallelism. But that's even more difficult and
  701. might cause more risks for incompatibility; and is the Mac hardware and software
  702. able to exploit that potential parallelism, or is everything serialized anyway ?.
  703. */
  704.  
  705.  
  706. short floppy_buffer_size;
  707.  
  708. static char* buffers_base;
  709. static sector_t first_in_buffer;
  710. static enum{empty, full, dirty };
  711. static char  *buffer_state;
  712. static Boolean traccia_difettosa;
  713.  
  714. void invalid_buffers(void);
  715. void invalid_buffers()
  716. {
  717. short i;
  718. for(i=0;i<floppy_buffer_size;i++)
  719.     buffer_state[i]=empty;
  720. first_in_buffer= -floppy_buffer_size;
  721. traccia_difettosa=false;
  722. }
  723.  
  724. void invalid_after(start_sector)
  725. sector_t start_sector;
  726. {
  727. short i;
  728. for(i=0;i<floppy_buffer_size;i++)
  729.     if(first_in_buffer+i >= start_sector) buffer_state[i]=empty;
  730. }
  731.  
  732.  
  733. void init_buffering()
  734. {
  735. ResrvMem ((Size)floppy_buffer_size);
  736. buffer_state=NewPtr((Size)floppy_buffer_size);
  737. invalid_buffers();
  738. buffers_base=NewPtr((Size)floppy_buffer_size*512);
  739. check_allocated(buffers_base);
  740. }
  741.  
  742. void check_allocated(p)
  743. void *p;
  744. {
  745. if(!p){
  746.     ParamText("\pCan\'t allocate disk buffers\rReduce their size or increase the partition",
  747.         PNS,PNS,PNS);
  748.     my_alert();
  749.     ExitToShell();
  750.     }
  751. }
  752.  
  753. void flush_buffers()
  754. {
  755. short primo=0, ultimo;
  756.  
  757. /*short i;for(i=0;i<floppy_buffer_size;i++)
  758.     printf("%d ",buffer_state[i]);
  759. printf("\n"); */
  760.  
  761. while(primo<floppy_buffer_size){
  762.     /* find a sequence of consecutive dirty sectors in buffer */
  763.     while(buffer_state[primo]!=dirty && primo<floppy_buffer_size) primo++;
  764.     if(primo>=floppy_buffer_size) break;
  765.     ultimo=primo+1;
  766.     while(ultimo<floppy_buffer_size && buffer_state[ultimo]==dirty ) ultimo++;
  767.     /*dp("write %ld,%ld\n",(long)(first_in_buffer+primo),(long)(first_in_buffer+ultimo-1));*/
  768.     write_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
  769.     if(err_code){
  770.         /*dp("errore, riprovo\n");*/
  771.         write_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
  772.         if(err_code){
  773.             invalid_buffers();
  774.             return;
  775.             }
  776.         }
  777.     if(verify_writes){
  778.         verify_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
  779.         if(err_code){
  780.             start_of_line();
  781.             printf("Write/verify: verification failed (sector");
  782.             if(primo==ultimo-1)
  783.                 printf(" %ld)\n",(long)(first_in_buffer+(long)primo));
  784.             else
  785.                 printf("s %ld to %ld)\n",(long)(first_in_buffer+(long)primo),
  786.                     first_in_buffer+(long)ultimo-1);
  787.             invalid_buffers();
  788.             raise_error();
  789.             }
  790.         }
  791.     primo=ultimo;
  792.     }
  793. invalid_buffers();
  794. err_code=0;
  795. }
  796.  
  797. Boolean dirty_buffers()
  798. {
  799. short i;
  800. for(i=0;i<floppy_buffer_size;i++)
  801.     if(buffer_state[i]==dirty) return true;
  802. return false;
  803. }
  804.  
  805. void leggi_settore(n_sect,buffer)
  806. /* read one sector, buffered */
  807. sector_t n_sect;
  808. char *buffer;
  809. {
  810. char *pos_in_buffer;
  811.  
  812. if(n_sect>=sectors_on_floppy){
  813.     err_code=n_sect==sectors_on_floppy?eofErr:    /* may happen for files, if there is not the cleared
  814.                         sector used as end-of-archive marker */
  815.         sectNFErr;
  816.     return;
  817.     }
  818.  
  819. if(n_sect>=first_in_buffer && n_sect<first_in_buffer+floppy_buffer_size){    /* match */
  820.     pos_in_buffer = buffers_base+((n_sect-first_in_buffer)<<9);
  821.  
  822.     if( buffer_state[n_sect-first_in_buffer]!=empty){
  823. /*dp("match lettura %ld\n",n_sect);*/
  824.         mcopy(buffer,pos_in_buffer,512);
  825.         err_code=noErr;
  826.         return;
  827.         }
  828.     if(traccia_difettosa){        /* defective sector on the track... */
  829.         read_sectors(n_sect, pos_in_buffer, 1);
  830.         /*dp("leggo 1\n");*/
  831.         mcopy(buffer,pos_in_buffer,512);
  832.         if(!err_code) buffer_state[n_sect-first_in_buffer]=full;
  833.         return;
  834.         }
  835.     }
  836.  
  837. flush_buffers();
  838. /* invalid_buffers(); */
  839.  
  840. traccia_difettosa=false;
  841. first_in_buffer= n_sect - n_sect%floppy_buffer_size;
  842. pos_in_buffer= buffers_base+((n_sect-first_in_buffer)<<9);
  843.  
  844.  
  845. if((fase==reading_disk||fase==hack_reading) && ! listonly || n_sect<=2){    /* sectors 0 and 2 are read
  846.         many times, it's better to read all of them even during a List */
  847.     short n_to_read;
  848.     /*dp(" leggo multiplo %ld\n",n_sect);*/
  849.     if(first_in_buffer+floppy_buffer_size<=sectors_on_floppy)
  850.         n_to_read= floppy_buffer_size;
  851.     else
  852.         n_to_read=sectors_on_floppy-first_in_buffer;
  853.     read_sectors(first_in_buffer,buffers_base,n_to_read);
  854.     if(! err_code){
  855.         short i;
  856.         for(i=0;i<n_to_read;i++)
  857.             buffer_state[i]=full;
  858.         for(;i<floppy_buffer_size;i++)
  859.             buffer_state[i]=empty;
  860.         mcopy(buffer,pos_in_buffer,512);
  861.         return;
  862.         }
  863.     traccia_difettosa=true;
  864.     }
  865.  
  866. /*dp(" leggo singolo (list)%ld\n",n_sect);*/
  867. read_sectors(n_sect, pos_in_buffer, 1);
  868. mcopy(buffer,pos_in_buffer,512);
  869. if(!err_code) buffer_state[n_sect-first_in_buffer]=full;
  870. }
  871.  
  872. void scrivi_settore(n_sect,buffer)
  873. /* write one sector, buffered */
  874. sector_t n_sect;
  875. char *buffer;
  876. {
  877. if(n_sect<first_in_buffer || n_sect>=first_in_buffer+floppy_buffer_size ){
  878. /*dp("chiedo flush %ld\n",n_sect);*/
  879.     flush_buffers();
  880.     if(err_code) return;
  881.     /* invalid_buffers(); */
  882.     first_in_buffer= n_sect - n_sect%floppy_buffer_size;
  883.     }
  884. /*else dp("match write %ld\n",n_sect);*/
  885. mcopy(buffers_base+((n_sect-first_in_buffer)<<9),buffer,512);
  886. buffer_state[n_sect-first_in_buffer]=dirty;
  887. err_code=noErr;
  888. return;
  889. }
  890.  
  891. /************** assembly language *******************************/
  892. /*
  893. #undef Sony_driver
  894. #define Sony_driver #-5
  895. */
  896.  
  897. #define ASM
  898. #undef ioRefNum
  899. #define ioDrvNum ioVRefNum
  900.  
  901. /* for suntar 1.0 we copied the examples in IM vol. II, which were in
  902. assembly language. Only for version 1.3.2 we wrote the equivalents in C.
  903.  That's the only reason to choose assembly rather than C */
  904.  
  905.  
  906. /* from Inside Macintosh volume II page 216 */
  907.  
  908.  
  909.  
  910. void diskEject()
  911. {
  912. ultimo_disco_espulso=true;
  913. disco_espulso=true;
  914. flush_buffers();
  915. if(drive_number==0) return;
  916.  
  917. #ifdef ASM
  918.     asm{
  919.         moveq    #31,D0  /* #<ioVQElSize/2>-1,D0 */
  920. clearloop:
  921.         clr.w    -(SP)
  922.         dbra    D0,@clearloop
  923.         move.l    SP,A0
  924.         move.w    Sony_driver,0x18(A0)    /* #-5,ioRefNum(A0) */
  925.         move.w    drive_number,0x16(A0)        /* drive_number,ioDrvNum(A0) */
  926.         move.w    #7,0x1A(A0)        /* #ejectCode,csCode(A0) */
  927.         dc.w 0xA017                /* _Eject */
  928.         add.w    #0x40,SP        /* #ioVQElSize,SP */
  929.     }
  930. #else
  931.     Eject(NULL,drive_number);
  932. #endif
  933. drive_number=0;
  934. }
  935.  
  936. /**********************************/
  937. void read_sectors(sect_n,buffer,n_sectors)
  938. short n_sectors;
  939.  
  940. sector_t sect_n;
  941. char *buffer;
  942. {
  943. long count;
  944.  
  945. if(file_aperto){
  946.     /* if working from a file rather than a disk... */
  947.  
  948. /* sectors_on_floppy is used to store the file length so that it's never
  949. called with a request for more than 511 bytes after EOF, in that case it
  950. clears those extra bytes and returns noErr. That's not a very good way to
  951. handle EOF, but suntar was written for disks, and in disks EOF is never
  952. placed inside a sector !
  953. */
  954.     err_code=0;
  955.     if(sect_n!=file_current_s)
  956.         err_code=SetFPos(inputFile,fsFromStart,(long)sect_n<<9);
  957.     if(err_code==eofErr)
  958.         err_code=sectNFErr;        /* sector not found error */
  959.     else if(!err_code){
  960.         count=(long)n_sectors<<9;
  961.         err_code=FSRead(inputFile,&count,buffer);
  962.         if(!err_code && !count) err_code=eofErr;
  963.         if(err_code==eofErr && count!=0){
  964.             fillmem(&buffer[count],0,(n_sectors<<9)-(short)count);
  965.             err_code=noErr;
  966.             file_current_s=-1;
  967.             return;
  968.             }
  969.         }
  970.     if(err_code)
  971.             file_current_s=-1;
  972.     else
  973.             file_current_s=sect_n+n_sectors;
  974.     return;
  975.     }
  976.  
  977. /* else, it's a floppy disk operation */
  978.  
  979. #ifdef ASM
  980. asm{
  981.     moveq    #24,D0             /* #<ioQElsize/2>-1,D0 */
  982. clrloop:    
  983.     clr.w    -(SP)
  984.     dbra    D0,@clrloop
  985.     move.l    SP,A0
  986.     move.w    Sony_driver,0x18(A0)    /* #-5,ioRefNum(A0) */
  987.     move.w    drive_number,0x16(A0)        /* drive_number,ioDrvNum(A0) */
  988.     move.w    #1,0x2C(A0)        /* #1,ioPosMode(A0) absolute positioning */
  989. #if SECTOR_T_SIZE==4
  990.     move.l    sect_n,D0
  991.     lsl.l    #4,D0            /* 9 is too big... */
  992.     lsl.l    #5,D0
  993. #else
  994.     move.w    sect_n,D0
  995.     mulu    #512,D0            /* does both short->long conversion and shift */
  996. #endif
  997.     move.l    D0,0x2E(A0)        /* D0,ioPosOffset(A0) */
  998.  
  999.     move.w    n_sectors,D0
  1000.     mulu    #512,D0
  1001.     move.l    D0,0x24(A0)        /* D0,ioReqCount(A0)    /* read n_sectors sectors */
  1002.     move.l    buffer,A1
  1003.     move.l    A1,0x20(A0)        /* A1,ioBuffer(A0) */
  1004.     dc.w 0xA002                /* _Read */
  1005.     move.w    0x10(A0),err_code    /* ioResult(A0),err_code */
  1006.     /*move.l  0x28(A0),count*/        /* ioActCount(A0),count) */
  1007.     add.w    #0x32,SP        /* #ioQElSize,SP */
  1008.     }
  1009. #else
  1010. {
  1011. ParamBlockRec pb;
  1012. fillmem(&pb,0,sizeof(pb));
  1013. pb.ioParam.ioRefNum=Sony_driver;
  1014. pb.ioParam.ioDrvNum=drive_number;
  1015. pb.ioParam.ioPosMode=fsFromStart;
  1016. pb.ioParam.ioPosOffset=((long)sect_n)<<9;
  1017. pb.ioParam.ioReqCount=((long)n_sectors)<<9;
  1018. pb.ioParam.ioBuffer=buffer;
  1019.  
  1020. PBReadSync(&pb);
  1021.  
  1022. err_code=pb.ioParam.ioResult;
  1023. /* count=pb.ioParam.ioActCount; */
  1024. }
  1025. #endif
  1026. }
  1027.  
  1028. void read_one_sector(sect_n,buffer,drive_n)
  1029. /* it reads from the disk even when read_sectors is redirected to read from a file... */
  1030. sector_t sect_n;
  1031. char *buffer;
  1032. short drive_n;
  1033. {
  1034.  
  1035. #ifdef ASM
  1036. asm{
  1037.     moveq    #24,D0             /* #<ioQElsize/2>-1,D0 */
  1038. clrloop:    
  1039.     clr.w    -(SP)
  1040.     dbra    D0,@clrloop
  1041.     move.l    SP,A0
  1042.     move.w    Sony_driver,0x18(A0)    /* #-5,ioRefNum(A0) */
  1043.     move.w    drive_n,0x16(A0)        /* drive_n,ioDrvNum(A0) */
  1044.     move.w    #1,0x2C(A0)        /* #1,ioPosMode(A0) absolute positioning */
  1045. #if SECTOR_T_SIZE==4
  1046.     move.l    sect_n,D0
  1047.     lsl.l    #4,D0            /* 9 is too big... */
  1048.     lsl.l    #5,D0
  1049. #else
  1050.     move.w    sect_n,D0
  1051.     mulu    #512,D0            /* does both short->long conversion and shift */
  1052. #endif
  1053.     move.l    D0,0x2E(A0)        /* D0,ioPosOffset(A0) */
  1054.  
  1055.     move.l    #512,0x24(A0)    /* #512,ioReqCount(A0) */
  1056.     move.l    buffer,A1
  1057.     move.l    A1,0x20(A0)        /* A1,ioBuffer(A0) */
  1058.     dc.w 0xA002                /* _Read */
  1059.     move.w    0x10(A0),err_code    /* ioResult(A0),err_code */
  1060.     add.w    #0x32,SP        /* #ioQElSize,SP */
  1061.  
  1062.     }
  1063. #else
  1064. ParamBlockRec pb;
  1065. fillmem(&pb,0,sizeof(pb));
  1066. pb.ioParam.ioRefNum=Sony_driver;
  1067. pb.ioParam.ioDrvNum=drive_n;
  1068. pb.ioParam.ioPosMode=fsFromStart;
  1069. pb.ioParam.ioPosOffset=((long)sect_n)<<9;
  1070. pb.ioParam.ioReqCount=512;
  1071. pb.ioParam.ioBuffer=buffer;
  1072.  
  1073. PBReadSync(&pb);
  1074.  
  1075. err_code=pb.ioParam.ioResult;
  1076. #endif
  1077. }
  1078.  
  1079.  
  1080. /******************************/
  1081.  
  1082. void write_sectors(sect_n,buffer,n_sectors)
  1083. sector_t sect_n;
  1084. char *buffer;
  1085. short n_sectors;
  1086. {
  1087. /*err_code=0;
  1088. return;*/
  1089.  
  1090. #ifdef ASM
  1091. asm{
  1092.     moveq    #24,D0             /* #<ioQElsize/2>-1,D0 */
  1093. clrloop:
  1094.     clr.w    -(SP)
  1095.     dbra D0,@clrloop
  1096.     move.l    SP,A0
  1097.     move.w    Sony_driver,0x18(A0)    /* #-5,ioRefNum(A0) */
  1098.     move.w    drive_number,0x16(A0)        /* drive_number,ioDrvNum(A0) */
  1099.     move.w    #1,0x2C(A0)        /* #1,ioPosMode(A0) absolute positioning */
  1100. #if SECTOR_T_SIZE==4
  1101.     move.l    sect_n,D0
  1102.     lsl.l    #4,D0
  1103.     lsl.l    #5,D0
  1104. #else
  1105.     move.w    sect_n,D0
  1106.     mulu    #512,D0
  1107. #endif
  1108.     move.l    D0,0x2E(A0)        /* D0,ioPosOffset(A0) */
  1109.  
  1110.     move.w    n_sectors,D0
  1111.     mulu    #512,D0
  1112.     move.l    D0,0x24(A0)        /* D0,ioReqCount(A0)    /* write n_sectors sectors */
  1113.     move.l    buffer,A1
  1114.     move.l    A1,0x20(A0)        /* A1,ioBuffer(A0) */
  1115.     dc.w 0xA003                /* _Write */
  1116.     move.w    0x10(A0),err_code    /* ioResult(A0),err_code */
  1117.     add.w    #0x32,SP        /* #ioQElSize,SP */
  1118.     }
  1119. #else
  1120. ParamBlockRec pb;
  1121. fillmem(&pb,0,sizeof(pb));
  1122. pb.ioParam.ioRefNum=Sony_driver;
  1123. pb.ioParam.ioDrvNum=drive_number;
  1124. pb.ioParam.ioPosMode=fsFromStart;
  1125. pb.ioParam.ioPosOffset=((long)sect_n)<<9;
  1126. pb.ioParam.ioReqCount=((long)n_sectors)<<9;
  1127. pb.ioParam.ioBuffer=buffer;
  1128.  
  1129. PBWriteSync(&pb);
  1130.  
  1131. err_code=pb.ioParam.ioResult;
  1132.  
  1133. #endif
  1134. }
  1135.  
  1136.  
  1137. static void verify_sectors(sect_n,buffer,n_sectors)
  1138. sector_t sect_n;
  1139. char *buffer;
  1140. short n_sectors;
  1141. {
  1142. #ifdef ASM
  1143. asm{
  1144.     moveq    #24,D0             /* #<ioQElsize/2>-1,D0 */
  1145. clrloop:    
  1146.     clr.w    -(SP)
  1147.     dbra    D0,@clrloop
  1148.     move.l    SP,A0
  1149.     move.w    Sony_driver,0x18(A0)    /* #-5,ioRefNum(A0) */
  1150.     move.w    drive_number,0x16(A0)        /* drive_number,ioDrvNum(A0) */
  1151.     move.w    #65,0x2C(A0)        /* #1+64,ioPosMode(A0) absolute positioning &
  1152.                                 read/verify */
  1153. #if SECTOR_T_SIZE==4
  1154.     move.l    sect_n,D0
  1155.     lsl.l    #4,D0            /* 9 is too big... */
  1156.     lsl.l    #5,D0
  1157. #else
  1158.     move.w    sect_n,D0
  1159.     mulu    #512,D0            /* does both short->long conversion and shift */
  1160. #endif
  1161.     move.l    D0,0x2E(A0)        /* D0,ioPosOffset(A0) */
  1162.  
  1163.     move.w    n_sectors,D0
  1164.     mulu    #512,D0
  1165.     move.l    D0,0x24(A0)        /* D0,ioReqCount(A0)    /* read n_sectors sectors */
  1166.     move.l    buffer,A1
  1167.     move.l    A1,0x20(A0)        /* A1,ioBuffer(A0) */
  1168.     dc.w 0xA002                /* _Read */
  1169.     move.w    0x10(A0),err_code    /* ioResult(A0),err_code */
  1170.     add.w    #0x32,SP        /* #ioQElSize,SP */
  1171.  
  1172.     }
  1173. #else
  1174. ParamBlockRec pb;
  1175. fillmem(&pb,0,sizeof(pb));
  1176. pb.ioParam.ioRefNum=Sony_driver;
  1177. pb.ioParam.ioDrvNum=drive_number;
  1178. pb.ioParam.ioPosMode=fsFromStart+rdVerify;    /* absolute positioning & read/verify */
  1179. pb.ioParam.ioPosOffset=((long)sect_n)<<9;
  1180. pb.ioParam.ioReqCount=((long)n_sectors)<<9;
  1181. pb.ioParam.ioBuffer=buffer;
  1182.  
  1183. PBReadSync(&pb);
  1184.  
  1185. err_code=pb.ioParam.ioResult;
  1186. #endif
  1187. }
  1188.  
  1189.  
  1190. /****************************************************************/
  1191.  
  1192. Boolean pStrCmpCi(unsigned char*,unsigned char*);
  1193. Boolean pStrCmpCi(s1,s2)
  1194. register unsigned char*s1,*s2;
  1195. /* a case insensitive Pascal string comparison, required by the following
  1196. routine (it's a matter of style, the original code used EqualString, and since
  1197. that may allocate memory it had to Lock the handles: in my own programming
  1198. style I prefer to write this small routine */
  1199. {
  1200. register short l=*s1++;
  1201. if(*s2++ != l) return false;    /* different length */
  1202. while(l--){
  1203.     register char c1=*s1++, c2=*s2++;
  1204.     if(c1 != c2){    /* they may still differ only in case... */
  1205.         if(c1>='A'&&c1<='Z') c1+= 'a'-'A';
  1206.         if(c2>='A'&&c2<='Z') c2+= 'a'-'A';
  1207.         if(c1 != c2) return false;
  1208.         }
  1209.     }
  1210. return true;
  1211. }
  1212.  
  1213.  
  1214. /********************
  1215.  
  1216.  From the snippet file "Floppy II", © Developers Technical Support, Apple
  1217.  
  1218. **********************/
  1219.  
  1220. #define kHandleBased        0x0040
  1221. #define UnitToRef(unitNo)        ( -(unitNo) - 1 )
  1222.  
  1223. typedef struct
  1224. {
  1225.     short        drvrFlags;        /* dReadEnable, etc */
  1226.     short        drvrDelay;        /* for periodic actions via SystemTask */
  1227.     short        drvrEMask;        /* for desk acc only */
  1228.     short        drvrMenu;        /* for desk acc only */
  1229.     short        drvrOpen;        /* offset to open routine */
  1230.     short        drvrPrime;        /* offset to prime routine */
  1231.     short        drvrCtl;        /* offset to control routine */
  1232.     short        drvrStatus;        /* offset to status routine */
  1233.     short        drvrClose;        /* offset to close routine */
  1234.     unsigned char drvrName[];    /* Pascal string */
  1235. } DriverHeader;
  1236.  
  1237.  
  1238. short FindDriverByName( void *pString )
  1239. {
  1240.     short            refNo;
  1241.     DCtlHandle        driverInfo;
  1242.     DriverHeader    *driverPtr, **driverHandle;
  1243.     short            unitNumber;
  1244.  
  1245. #ifdef THINK_C_5
  1246.     #define numEntriesInTable (*( (short*)UnitNtryCnt ))
  1247.     /* UnitNtryCnt is a constant in sysEqu.h */
  1248. #else
  1249.     #define numEntriesInTable UnitNtryCnt
  1250.     /* UnitNtryCnt is a variable in DeviceMgr.h */
  1251. #endif
  1252.  
  1253.     /* to find .Sony, one must search backwards: for historical reasons
  1254.     there are two .Sony drivers, -5 and -2, and -5 is the one normally
  1255.     used for floppy disks (-2 was used by Apple HD20, a product no more
  1256.     sold since about 1985). That means skipping a lot of empty entries,
  1257.     but this routine is called only once */
  1258.     for ( unitNumber=numEntriesInTable-1; unitNumber; unitNumber-- ) {
  1259.         refNo = UnitToRef(unitNumber);
  1260.         driverInfo = GetDCtlEntry(refNo);
  1261.         if (driverInfo) {
  1262.             if ((**driverInfo).dCtlFlags & kHandleBased ) {
  1263.                 driverHandle = (void *)(**driverInfo).dCtlDriver;
  1264.                 if (!driverHandle || !(*driverHandle))
  1265.                     continue;
  1266.  
  1267.                 if (pStrCmpCi(pString, (**driverHandle).drvrName))
  1268.                     return refNo;
  1269.                 /*pStrcpy(disk_buffer,(**driverHandle).drvrName);
  1270.                 printf("%P\n",disk_buffer);*/
  1271.                 }
  1272.             else {
  1273.                 driverPtr = (void*)(**driverInfo).dCtlDriver;
  1274.                 if ( !driverPtr ) 
  1275.                     continue;
  1276.  
  1277.                 if ( pStrCmpCi( pString, driverPtr->drvrName ) )
  1278.                     return refNo;
  1279.                 /*printf("%P\n",driverPtr->drvrName);*/
  1280.                 }
  1281.             }
  1282.         }
  1283.     return 0;
  1284. }
  1285.